#ifndef __OPENIMG_OPENCL_H__
#define __OPENIMG_OPENCL_H__

namespace img {
	namespace ocl {
		enum DeviceType
		{
			DEVICE_TYPE_DEFAULT = (1 << 0),
			DEVICE_TYPE_CPU = (1 << 1),
			DEVICE_TYPE_GPU = (1 << 2),
			DEVICE_TYPE_ACCELERATOR = (1 << 3),
			//CVCL_DEVICE_TYPE_CUSTOM      = (1 << 4)
			DEVICE_TYPE_ALL = 0xFFFFFFFF
		};

		enum DevMemRW
		{
			DEVICE_MEM_R_W = 0,
			DEVICE_MEM_R_ONLY,
			DEVICE_MEM_W_ONLY
		};

		enum DevMemType
		{
			DEVICE_MEM_DEFAULT = 0,
			DEVICE_MEM_AHP,         //alloc host pointer
			DEVICE_MEM_UHP,         //use host pointer
			DEVICE_MEM_CHP,         //copy host pointer
			DEVICE_MEM_PM           //persistent memory
		};

		enum FEATURE_TYPE
		{
			FEATURE_CL_DOUBLE = 1,
			FEATURE_CL_UNIFIED_MEM,
			FEATURE_CL_VER_1_2,
			FEATURE_CL_INTEL_DEVICE
		};

		/*																										//
		//---------------------------------------PlantformsInfo---------------------------------------------------//
		*/																										//
		struct DeviceInfo;

		struct PlatformInfo
		{
			int _id; // reserved, don't use it

			std::string platformProfile;
			std::string platformVersion;
			std::string platformName;
			std::string platformVendor;
			std::string platformExtensons;

			int platformVersionMajor;
			int platformVersionMinor;

			std::vector<const DeviceInfo*> devices;

			PlatformInfo();
			~PlatformInfo();
		};
		typedef std::vector<const PlatformInfo*> PlatformsInfo;
		OCL_EXPORTS int getOpenCLPlatforms(PlatformsInfo& platforms);

		/*																										//
		//---------------------------------------DevicesInfo---------------------------------------------------//
		*/
		struct DeviceInfo
		{
			int _id; // reserved, don't use it

			DeviceType deviceType;
			std::string deviceProfile;
			std::string deviceVersion;
			std::string deviceName;
			std::string deviceVendor;
			int deviceVendorId;
			std::string deviceDriverVersion;
			std::string deviceExtensions;

			size_t maxWorkGroupSize;
			std::vector<size_t> maxWorkItemSizes;
			int maxComputeUnits;
			size_t localMemorySize;
			size_t maxMemAllocSize;

			int deviceVersionMajor;
			int deviceVersionMinor;

			bool haveDoubleSupport;
			bool isUnifiedMemory; // 1 means integrated GPU, otherwise this value is 0
			bool isIntelDevice;

			std::string compilationExtraOptions;

			const PlatformInfo* platform;

			DeviceInfo();
			~DeviceInfo();
		};
		typedef std::vector<const DeviceInfo*> DevicesInfo;

		OCL_EXPORTS int getOpenCLDevices(DevicesInfo& devices, int deviceType = DEVICE_TYPE_GPU,
			const PlatformInfo* platform = NULL);

		class OCL_EXPORTS Context
		{
		protected:
			Context() { }
			~Context() { }
		public:
			static Context* getContext();

			bool supportsFeature(FEATURE_TYPE featureType) const;
			const DeviceInfo& getDeviceInfo() const;

			const void* getOpenCLContextPtr() const;
			const void* getOpenCLCommandQueuePtr() const;
			const void* getOpenCLDeviceIDPtr() const;
		};

		OCL_EXPORTS void setDevice(const DeviceInfo* info);
	}
}
#endif // !__OPENIMG_OPENCL_H__
